package org.yypm;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultText;
import org.xml.sax.InputSource;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 云烟飘渺o
 * @version 1.0
 * @description 借巨人之力，加速你的成长之路
 * 1. 解析出一个Configuration
 * 2. 构建返回一个SqlSessionFactory
 */
public class SqlSessionFactoryBuilder {


    /**
     * String resource = "mybatis-config-datasource.xml";
     *
     * @param resource
     * @return
     */
    public DefaultSqlSessionFactory build(String resource) {
        try {
            Reader resourceAsReader = Resources.getResourceAsReader(resource);
            SAXReader saxReader = new SAXReader();
            InputSource inputSource = new InputSource(resourceAsReader);
            Document read = saxReader.read(inputSource);
            Element rootElement = read.getRootElement();
            Configuration configuration = parseConfiguration(rootElement);
            return new DefaultSqlSessionFactory(configuration);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private Configuration parseConfiguration(Element rootElement) {
        Map<String, String> dataSource = dataSource(rootElement.selectNodes("//dataSource"));
        Map<String, XNode> mapperElements = mapperElements(rootElement.selectNodes("//mappers"));
        Connection connection = connection(dataSource);
        return new Configuration(connection, dataSource, mapperElements);
    }


    private Map<String, String> dataSource(List<Element> list) {
        Map<String, String> dataSource = new HashMap<>(4);
        Element element = list.get(0);
        List content = element.content();
        for (Object o : content) {
            if (o instanceof DefaultText) {
                continue;
            }
            Element e = (Element) o;
            String name = e.attributeValue("name");
            String value = e.attributeValue("value");
            dataSource.put(name, value);
        }
        return dataSource;
    }

    private Map<String, XNode> mapperElements(List<Element> list) {
        Map<String, XNode> mapperElements = new HashMap<>();
        Element element = list.get(0);
        List content = element.content();
        try {
            for (Object o : content) {
                if (o instanceof DefaultText) {
                    continue;
                }
                Element e = (Element) o;
                String resource = e.attributeValue("resource");
                Reader resourceAsReader = Resources.getResourceAsReader(resource);
                SAXReader saxReader = new SAXReader();
                Document read = saxReader.read(new InputSource(resourceAsReader));
                Element rootElement = read.getRootElement();

                String namespace = rootElement.attributeValue("namespace");
                List<Element> select = rootElement.selectNodes("select");

                for (Element selectElement : select) {
                    String id = selectElement.attributeValue("id");
                    String resultType = selectElement.attributeValue("resultType");
                    String parameterType = selectElement.attributeValue("parameterType");
                    String sql = selectElement.getText();

                    Map<Integer, String> parameterMap = new HashMap<>();
                    Pattern pattern = Pattern.compile("(#\\{(.*?)})");
                    Matcher matcher = pattern.matcher(sql);
                    for (int i = 1; matcher.find(); i++) {
                        String g1 = matcher.group(1);
                        String g2 = matcher.group(2);
                        parameterMap.put(i, g2);
                        sql = sql.replace(g1, "?");
                    }
                    XNode xNode = new XNode();
                    xNode.setNameSpace(namespace);
                    xNode.setId(id);
                    xNode.setResultType(resultType);
                    xNode.setSql(sql);
                    xNode.setParameter(parameterMap);
                    xNode.setParameterType(parameterType);
                    mapperElements.put(namespace + "." + id, xNode);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mapperElements;
    }


    private Connection connection(Map<String, String> dataSource) {
        try {
            Class.forName(dataSource.get("driver"));
            return DriverManager.getConnection(dataSource.get("url"), dataSource.get("username"), dataSource.get("password"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
